﻿namespace DimensionsHelper.Client.WinUi.ViewModels;

public abstract partial class ProjectViewModel<T> : RecordHistoryViewModel, IProjectViewModel where T : class, new()
{
    protected ProjectViewModel()
    {
        PresetList = [];
        InitializePresetFiles();
    }


    protected override string[] FileFilters =>
    [
        Common.Utils.FileFilters.Json
    ];


    [ObservableProperty]
    public partial bool IsCurrentJsonPreset
    {
        get;
        set;
    }


    /// <summary>
    ///     预设配置文件名列表
    /// </summary>
    public ObservableCollection<OptionalFileViewModel> PresetList
    {
        get;
    }


    /// <summary>
    ///     获取序列化和反序列化配置对象时使用的Json类型信息。
    /// </summary>
    protected abstract JsonTypeInfo<T> JsonTypeInfo
    {
        get;
    }


    public virtual Task BuildTask(IReportService reportService, CancellationToken cancellationToken)
    {
        return new Task(() =>
        {
            if (!OnProjectObjectPreparing(reportService))
            {
                return;
            }

            DateTime startTime = DateTime.Now;

            IProjectBase<T> project = GetProjectObject();
            project.FilePikerService = App.GetService<IFilePikerService>();
            project.ReportService = reportService;

            string? taskId = null;

            if (reportService is IProjectTask projectTask)
            {
                taskId = projectTask.Id;
            }

            T option = new();
            if (!TryWriteOption(option, reportService))
            {
                App.ShowErrorNotification(
                    ResourceKeys.AppSettingsLoadingErrorMessage.GetLocalized(),
                    typeof(TaskInformationViewModel), taskId);
                return;
            }

            if (!project.LoadSettings(option))
            {
                App.ShowErrorNotification(
                    ResourceKeys.AppProjectLoadingErrorMessage.GetLocalized(),
                    typeof(TaskInformationViewModel), taskId);
                return;
            }

            OnProjectObjectStarting(project, cancellationToken);

            if (App.NotifyWhenTaskFinished())
            {
                App.ShowNotification(Section,
                    cancellationToken.IsCancellationRequested
                        ? ResourceKeys.AppTaskCanceledMessage.GetLocalized()
                        : ResourceKeys.AppTaskFinishedMessage.GetLocalized(),
                    typeof(TaskInformationViewModel), taskId);
            }

            if (cancellationToken.IsCancellationRequested)
            {
                reportService.Log(ResourceKeys.AppTaskCanceledMessage.GetLocalized());
            }
            else
            {
                reportService.Log(ResourceKeys.AppTaskFinishedMessage.GetLocalized(), "");
            }
        }, cancellationToken);
    }


    private async void InitializePresetFiles()
    {
        try
        {
            foreach (string preset in await OptionalFileService.GetPresetNamesAsync())
            {
                OptionalFileViewModel presetFile = new()
                {
                    FileName = preset
                };

                presetFile.Selected += OnOptionalFileSelected;
                presetFile.Unselected += OnOptionalFileUnselected;

                PresetList.Add(presetFile);
            }
        }
        catch (Exception e)
        {
            await App.ShowErrorMessage(e);
        }
    }


    protected async override Task<bool> OnCurrentFileNameChangedOverride(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return false;
        }

        try
        {
            string content;

            if (await OptionalFileService.IsPresetAsync(value))
            {
                content = await StorageHelper.LoadText($"Assets/{OptionalFileService.StorageRoot}/{value}.json");
                IsCurrentJsonPreset = true;
            }
            else
            {
                IsCurrentJsonPreset = false;

                if (!App.GetService<IFileService>().Exists(value))
                {
                    return false;
                }

                content = App.GetService<IFileService>().Read(value, Encoding.UTF8);
            }

            T? option = App.GetService<IFileService>().Deserialize(content, JsonTypeInfo);

            if (option is null)
            {
                return false;
            }

            LoadOption(option, App.GetGlobalTask());
            return !IsCurrentJsonPreset;
        }
        catch (Exception)
        {
            return false;
        }
    }


    /// <summary>
    ///     获取任务对象，泛型参数<see cref="T" />是可以从json转换的配置对象。
    /// </summary>
    protected abstract IProjectBase<T> GetProjectObject();


    private async Task SaveOrSaveAsJson(bool saveAs)
    {
        if (saveAs || string.IsNullOrEmpty(CurrentFileName) || await OptionalFileService.IsPresetAsync(CurrentFileName))
        {
            string? selectedPath = await App.GetService<IFilePikerService>()
                .SaveFileAsync(FileFilters);
            if (string.IsNullOrEmpty(selectedPath))
            {
                return;
            }

            UpdatingInternal = true;
            CurrentFileName = selectedPath;
            UpdatingInternal = false;
        }

        T options = new();

        if (!TryWriteOption(options, App.GetGlobalTask()))
        {
            App.ShowErrorNotification(
                ResourceKeys.AppSettingsLoadingErrorMessage.GetLocalized(),
                typeof(TaskInformationPage),
                App.GlobalTaskId);

            return;
        }

        try
        {
            string dir = Path.GetDirectoryName(CurrentFileName)!;

            App.GetService<IFileService>().Save(CurrentFileName, JsonTypeInfo, options);
            App.GetGlobalTask().Directory(
                CurrentFileName,
                ResourceKeys.AppJsonExportFinishedMessage.GetLocalized(),
                CurrentFileName);

            if (App.NotifyWhenTaskFinished())
            {
                App.ShowDirectoryNotification(
                    ResourceKeys.AppSettingsFileExportSuccessfullyMessage.GetLocalized(),
                    CurrentFileName, dir);
            }
        }
        catch (Exception e)
        {
            await App.GetService<IMessageService>().ShowAsync(e.Message, ResourceKeys.AppErrorLabel.GetLocalized());
        }
    }


    protected async override Task SaveFile() => await SaveOrSaveAsJson(false);


    [RelayCommand]
    private async Task SaveFileAs() => await SaveOrSaveAsJson(true);


    protected abstract bool TryWriteOption(T target, IReportService reportService);

    protected abstract void LoadOption(T source, IReportService reportService);


    protected virtual bool OnProjectObjectPreparing(IReportService reportService) => true;


    protected virtual void OnProjectObjectStarting(IProjectBase<T> projectObject, CancellationToken cancellationToken)
    {
    }


    [RelayCommand]
    internal void Start() => WeakReferenceMessenger.Default.Send((IProjectViewModel)this);
}